package cn.chaos.nio.exercise;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.URLConnection;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;

public class JHttpServerNio2 {


    private ByteBuffer contentBuffer;
    private int port = 11111;

    public JHttpServerNio2(ByteBuffer data, String encoding, String MimeType, int port) {
        this.port = port;
        String header = "HTTP/1.1 200 OK\r\n" +
                "Server: JHttpServerNio2\r\n" +
                "Content-Length: "+ data.limit() + "\r\n" +
                "Content-Type: "+ MimeType + "\r\n\r\n";

        byte[] headerData = header.getBytes(StandardCharsets.US_ASCII);

        ByteBuffer buffer = ByteBuffer.allocate(data.capacity() + headerData.length);

        buffer.put(headerData);
        buffer.put(data);
        buffer.flip();
        this.contentBuffer = buffer;
    }

    public void run() throws IOException {


        ServerSocketChannel serverChannel = ServerSocketChannel.open(); // NOSONAR
        ServerSocket serverSocket = serverChannel.socket();
        Selector selector = Selector.open();    // NOSONAR
        InetSocketAddress localPort = new InetSocketAddress(port);
        serverSocket.bind(localPort);
        serverChannel.configureBlocking(false);
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true && serverChannel != null) {
            int select = selector.select(1000);
            System.out.println("select = "+ select);
            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
            while (keys.hasNext()) {
                SelectionKey key = keys.next();
                keys.remove();

                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel channel = server.accept();
                        channel.configureBlocking(false);
                        channel.register(selector, SelectionKey.OP_READ);
                    } else if (key.isWritable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        while (buffer.hasRemaining()) {
                            channel.write(buffer);
                        }
                        channel.close();

                    } else if (key.isReadable()) {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(8);
                        if (channel.read(buffer) == -1) {
                            System.out.println("close ...");
                            channel.close();
                            continue;
                        }
                        StringBuilder sb = new StringBuilder();
                        String end = null;
                        while ( channel.read(buffer)  != -1 ) {
                            buffer.flip();
                            while (buffer.hasRemaining()) {
                                sb.append((char)buffer.get());
                            }
                            buffer.clear();
                            if (sb.length() > 4) {
                                end = sb.substring(sb.length() -4);
                            }
                            if (end != null && (end.endsWith("\n\r\n") || end.endsWith("\n\n"))) {
                                break;
                            }
                        }
                        System.out.println(sb);

                        // 将通道切换为只写模式
                        key.interestOps(SelectionKey.OP_WRITE);
                        key.attach(contentBuffer.duplicate());
                    }
                } catch (IOException e) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) {

        int port = 11111;
        Path file = FileSystems.getDefault().getPath("/Users/chengchao/temp/mydocroot/spring.html");
        String contentType = URLConnection.getFileNameMap().getContentTypeFor(file.toFile().getName());
        try {
            byte[] data = Files.readAllBytes(file);
            ByteBuffer input = ByteBuffer.wrap(data);
            String encoding = "UTF-8";
            JHttpServerNio2 server = new JHttpServerNio2(input, encoding,contentType, port);
            server.run();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
